package com.wpre.vampiremq.mqserver.core;

import com.wpre.vampiremq.common.MQException;

/**
 * Created with IntelliJ IDEA.
 * Description:实现交换机的转发规则,验证bindingKey的合法性
 * User: LianBao
 * Date: 2025-01-17
 * Time: 15:01
 */
public class Router {
    //数字字母下划线
    //.
    //# 和 * 作为通配符
    public boolean checkBindingKey(String bindingKey) {


        if (bindingKey.length()==0) {
            //空字符串,合法,因为如果是FANOUT,此时bindingKey就用不上,会置为空
            //DIRECT交换机,直接把routingKey当成队列名,bindingKey用不上
            return true;
        }
        for (int i = 0; i < bindingKey.length(); i++) {
            char ch = bindingKey.charAt(i);
            //判断是否是字母
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }

            //判断是否是数字
            if (ch >= '0' && ch <= '9') {
                continue;
            }

            //下划线或者.
            if (ch == '_' || ch == '.' || ch == '*' || ch == '#') {
                continue;
            }
            //如果该字符不是上述任何一种合法情况,就返回false
            return false;
        }
        //检查# 或 * 是否是独立部分
        //根据 . 把字符串分割出来
        String[] words = bindingKey.split("\\.");//对\转义,再对.转义
        for (String word : words) {
            if (word.length() > 1 && (word.contains("*") || word.contains("#"))) {
                //如果分割之后,还包含# * ,就是不合法的
                return false;
            }
        }
        //约定 通配符之间的相邻关系
        //1. aaa.#.#.bbb ==> 非法
        //2. aaa.#.*.bbb ==> 非法
        //3. aaa.*.#.bbb ==> 非法
        //4. aaa.*.*.bbb ==> 合法
        //因为,4这种情况实现起来比较简单
        for (int i = 0; i < words.length - 1; i++) {
            if ("#".equals(words[i]) && "#".equals(words[i + 1])) {
                return false;
            }
            if ("#".equals(words[i]) && "*".equals(words[i + 1])) {
                return false;
            }
            if ("*".equals(words[i]) && "#".equals(words[i + 1])) {
                return false;
            }
        }
        return true;
    }

    //routingKey:数字,字母下划线组成
    //使用 . 分割成 若干个部分
    public boolean checkRoutingKey(String routingKey) {
        if (routingKey.isEmpty()) {
            //空字符串,合法,因为如果是FANOUT,此时routingKey就用不上,会置为空
            return true;
        }
        for (int i = 0; i < routingKey.length(); i++) {
            char ch = routingKey.charAt(i);
            //判断是否是字母
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }

            //判断是否是数字
            if (ch >= '0' && ch <= '9') {
                continue;
            }

            //下划线或者.
            if (ch == '_' || ch == '.') {
                continue;
            }
            //如果该字符不是上述任何一种合法情况,就返回false
            return false;
        }

        return true;
    }

    //判断当前消息能否能够进行转发到对应的队列
    public boolean route(ExchangeType type, Binding binding, Message message) {

        // 根据不同的ExchangeType 使用不同的判断转发规则
        if (type == ExchangeType.FANOUT) {
            //FANOUT,需要转发给所有的队列,直接返回true
            return true;

        } else if (type == ExchangeType.TOPIC) {
            //TOPIC,主体交换机
            return routTOPIC(binding, message);

        } else {
            //其他情况(不应该出现的情况)
            throw new MQException("交换机类型非法");
        }

    }

    //判断TOPIC交换机类型能否执行转发操作
    private boolean routTOPIC(Binding binding, Message message) {
        String[] bindingKeySplit = binding.getBindingKey().split("\\.");
        String[] routingKeySplit = message.getRoutingKey().split("\\.");
        int bindIndex = 0;
        int routIndex = 0;
        while (bindIndex < bindingKeySplit.length && routIndex < routingKeySplit.length) {
            //遇到* 跳过下一个
            if ("*".equals(bindingKeySplit[bindIndex])) {
                bindIndex++;
                routIndex++;
                continue;
            } else if ("#".equals(bindingKeySplit[bindIndex])) {
                //遇到#号
                //判断有没有下一个位置
                bindIndex++;
                if (bindIndex == bindingKeySplit.length) {
                    // 判断有没有下一个位置,如果没有就直接返回
                    return true;
                }
                //找routingKeySplit中有没有当前bindIndex位置的元素
                routIndex = findNextMatch(routingKeySplit, routIndex, bindingKeySplit[bindIndex]);
                if (routIndex == -1) {
                    //没找到匹配结果,匹配失败
                    return false;
                }
                //找到了就继续往后匹配,
                bindIndex++;
                routIndex++;
            } else {
                //普通字符串,要求两个内容都一样
                if (!bindingKeySplit[bindIndex].equals(routingKeySplit[routIndex])) {
                    return false;
                }
                //如果匹配继续往后
                bindIndex++;
                routIndex++;
            }

        }
        //判断是否是双方同时到达末尾
        if (bindIndex == bindingKeySplit.length && routIndex == routingKeySplit.length) {
            return true;
        }
        return false;
    }


    private int findNextMatch(String[] routingKeySplit, int routIndex, String bindingKeySplit) {
        //routingKeySplit, routIndex, bindingKeySplit[bindIndex]
        for (int i = routIndex; i < routingKeySplit.length; i++) {
            if (bindingKeySplit.equals(routingKeySplit[i])) {
                return i;
            }
        }
        return -1;
    }
}
